Network Extension

RSS for tag

Customize and extend the core networking features of iOS, iPad OS, and macOS using Network Extension.

Posts under Network Extension tag

200 Posts

Post

Replies

Boosts

Views

Activity

Network Extension Resources
General: Forums subtopic: App & System Services > Networking DevForums tag: Network Extension Network Extension framework documentation Routing your VPN network traffic article Filtering Network Traffic sample code TN3120 Expected use cases for Network Extension packet tunnel providers technote TN3134 Network Extension provider deployment technote TN3165 Packet Filter is not API technote Network Extension and VPN Glossary forums post Debugging a Network Extension Provider forums post Exporting a Developer ID Network Extension forums post Network Extension Framework Entitlements forums post Network Extension vs ad hoc techniques on macOS forums post Network Extension Provider Packaging forums post NWEndpoint History and Advice forums post Extra-ordinary Networking forums post URL filter: WWDC 2025 Session 234 Filter and tunnel network traffic with NetworkExtension URL filters documentation Filtering traffic by URL sample code Setting up a PIR server for URL filtering sample code Using the Bloom filter tool to configure a URL filter sample code PIR Service Example open source server sample and specifically its documentation Wi-Fi management: Understanding NEHotspotConfigurationErrorInternal forums post See also Networking Resources for general networking resources, including information about Wi-Fi. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
3.9k
4w
NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Hi, My NEURL Filter configuration (ID 9f3cbff8-63de-4c69-bf68-c19cd1c5d842) was approved on August 5, 2026, but it turned out to be attached to the wrong Apple Developer Team — an old individual account (S5VDH23BBZ) I no longer have access to, instead of my actual organization team, KRKJ76BC7W (SCOTTO), which owns and signs the app (bundle ID com.dropbet.DropBet). I contacted Developer Support, who said they couldn't transfer it and suggested replying to the original approval email — I did (on 08/08, then several times) with no response. I then tried resubmitting the same configuration under the correct team (KRKJ76BC7W), but the portal rejected it with: "A configuration with the same PIR Server Domain already exists." So a fresh submission is technically impossible while the original stays attached to the wrong account — the only real fix is transferring or re-attaching the existing approved configuration to KRKJ76BC7W. Has anyone dealt with this kind of Team ID mix-up before, or know who on the Network Extension / NEURL Filter team could help reassign an approved configuration? Happy to provide any additional details. Thanks in advance.
5
0
702
14h
Does "Connectivity Assist" bypass NEPacketTunnelProvider DNS interception on iOS 27?
We have a NEPacketTunnelProvider extension that intercepts and modifies DNS responses for specific hostnames as part of its normal operation. On iOS 27, we are seeing this interception being intermittently bypassed. Our extension still receives the DNS query, builds a response, and returns it promptly, but the client occasionally proceeds using a different address, presumably the actual DNS resolution result. This behavior does not reproduce on iOS 26 or earlier. The timing in our logs appears to correlate with the new Connectivity Assist feature (Settings → Wi-Fi), which Apple describes as using cellular data alongside Wi-Fi to improve reliability. Our suspicion is that Connectivity Assist may be performing DNS resolution over a cellular path in parallel, outside the tunnel, causing that resolution path to bypass our provider entirely. We have ruled out response timing and response format issues on our side. Varying the speed and format of our responses does not affect the outcome, suggesting that the behavior is occurring at a layer above the tunnel provider. We have the following questions: Does Connectivity Assist perform DNS resolution on a network path that can bypass an active NEPacketTunnelProvider? Is there any API, entitlement, or supported mechanism to disable Connectivity Assist for an app, or to ensure that all DNS resolution is routed through the active tunnel, similar to previous Wi-Fi Assist opt-out capabilities? Would a NEDNSProxyProvider-based DNS proxy be affected in the same way, or does it operate at a layer that Connectivity Assist cannot bypass? Any guidance, references to relevant documentation, WWDC session content, or confirmation of the expected behavior would be greatly appreciated.
2
0
52
15h
NEURLFilter & Live Caller ID Lookup approved, but PIR token issuer directory returns 404 on device — filter never activates (serverSetupIncomplete)
Our NEURLFilter (URL Filter) and Live Caller ID Lookup entitlements are both Approved, but on device the URL filter never activates — the NEURLFilter session loops starting → stopped, so no URLs are filtered. App: bundle app.scamzero (App ID 6768433709) URL Filter Config ID: 224e33c9-b03b-44ce-87cd-2153c86908ce Live Caller ID Lookup Config ID: 0abdc42b-c98b-4753-8af4-9334d42abdb8 Device: iPhone on iOS 26. Test account has the paid plan that enables the feature. The system log shows the failure is fetching the Privacy Pass token issuer directory through Apple's relay (gateway.icloud.com), not our backend: ciphermld : Failed to fetch Token Issuer Directory. URL: https://gateway.icloud.com/pat-issuer-directory?issuer=issuer.scamzero.app Status Code: 404 → NEURLFilterPlugin setStatus:error — NEAgentURLFilterErrorDomain Code=3 → NESMURLFilterSession status changed to stopping with error 3 → prefilterCleanup (removes the prefilter mmap) → session restarts → loop This looks like NEURLFilterManager.Error.serverSetupIncomplete (9). What we have already verified on our side (everything conforms): We run Apple's unmodified reference PIRService (from apple/pir-service-example). Our issuer directory at https://issuer.scamzero.app/.well-known/private-token-issuer-directory returns 200 with valid token-keys (token-type 2) and issuer-request-uri. OHTTP gateway (gateway.scamzero.app/ohttp-configs and /gateway), PIR service (service.scamzero.app), use case app.scamzero.url.filtering, bearer token AAAA, DNS TXT apple-url-filter=app.scamzero, and the validation URL apple.com/url-filter-test = 1 are all configured. Our pre-launch checks pass. The precomputed Bloom prefilter loads on device with the correct bit/hash/seed and ~37k domains. Key observation: our OHTTP gateway logs show zero successful OHTTP requests from Apple's infrastructure since Aug 10, and gateway.icloud.com/pat-issuer-directory?issuer=issuer.scamzero.app returns 404 on device. This suggests our Privacy Pass issuer is not registered/validated in Apple's PAT issuer directory, even though both entitlements are Approved. Question: How can we get our Privacy Pass issuer (issuer.scamzero.app) registered/validated in Apple's token issuer directory for the use cases app.scamzero.url.filtering and Live Caller ID Lookup? The entitlements are approved, but the on-device token issuer directory lookup fails with 404, which prevents the filter from ever activating. Happy to file a Feedback with a sysdiagnose if useful.
1
0
79
21h
nesessionmanager infinite retry loop causes permanent, unfixable Local Network Access denial (System Settings UI misrepresents actual enforcement state)
Summary On macOS 26.6.2 (25G83) (Tahoe), Chrome fails to load pages hosted on private/local IP addresses (e.g. http://192.168.0.43/, a home AV receiver's web setup page) with ERR_ADDRESS_UNREACHABLE, while Safari loads the identical URL without issue on the same Mac, same network. ping to the target IP succeeds normally. System Settings > Privacy & Security > Local Network shows "Allow" for Chrome — but this is not what's actually being enforced. Traced the root cause to nesessionmanager stuck in an infinite retry loop when attempting to install/update NetworkExtension path-rule policies. Because the daemon never completes a successful policy install, nehelper (the actual enforcement point) continues serving a stale cached "denied" decision indefinitely, regardless of what the Settings UI shows or how many times the toggle is flipped. Key evidence Chrome netlog (chrome://net-export/) shows a genuine TCP connect attempt (not an early permission rejection): text TCP_CONNECT_ATTEMPT --> address = "192.168.0.43:80" -TCP_CONNECT_ATTEMPT --> os_error = 65 -TCP_CONNECT --> net_error = -109 (ERR_ADDRESS_UNREACHABLE) os_error = 65 is BSD EHOSTUNREACH, returned by the kernel at the connect() syscall. Unified log (log stream --predicate 'subsystem == "com.apple.networkextension"') shows the actual enforcement decision: text nehelper: UUID cache hit for com.google.Chrome nehelper: Local network denied by preference for Google Chrome (com.google.Chrome) This reproduced identically across multiple attempts, minutes apart, and survived sudo pkill -f nehelper — confirming the decision is persisted, not just an in-memory cache. While toggling the Local Network switch in System Settings, expecting a pathRules dump, the log instead showed: text NESMPathControllerSession[...]: No UUIDs in the cache for PathRuleDefaultNonSystemIdentifier, populating the cache from the path rules NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 1 NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 2 NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 3 NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 4 NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 5 The retry counter kept incrementing with no observed successful completion, meaning any change made via the System Settings toggle can never actually propagate to nehelper. Also confirmed Local Network privacy is not TCC-backed at all: text $ sudo tccutil reset LocalNetwork tccutil: Failed to reset LocalNetwork $ sudo tccutil reset LocalNetwork com.google.Chrome tccutil: Failed to reset LocalNetwork approval status for com.google.Chrome Both fail outright rather than erroring on bad usage, confirming this permission lives entirely in the NetworkExtension path-rule system, with no supported reset command. What did not fix it Toggling the Settings UI switch off/on sudo tccutil reset SystemPolicyNetworkVolumes (wrong TCC service — doesn't apply here) sudo tccutil reset LocalNetwork (fails, see above) Full clean reinstall of Chrome, including all Application Support/Caches/Preferences Safe Mode boot sudo pkill -f nehelper Full normal system restart Launching Chrome with --no-sandbox (rules out Chromium's own internal sandbox as a factor — this is a system-level enforcement, not a Chromium-side block) Working fix Requires temporarily disabling SIP: text In macOS Recovery (csrutil only works from Recovery, not Safe Mode): csrutil disable Back in normal macOS: sudo rm /Library/Preferences/com.apple.networkextension.plist Back in Recovery: csrutil enable Restart normally. nesessionmanager rebuilds the NetworkExtension policy state from scratch on next boot. System Settings > Privacy & Security > Local Network shows a clean list afterward (also clears the separate, previously-known bug where every Chrome auto-update was creating a new duplicate entry in that list rather than updating the existing one). Chrome's next navigation attempt to a local IP correctly triggers a fresh permission prompt, and functions normally once granted. Why this matters Apple's own TN3179 states there's no supported way to reset an app's Local Network privilege to "undetermined." This bug compounds that: once nesessionmanager gets stuck in this retry loop, there is no path back to a working state short of disabling SIP and manually deleting a system preference file. The Settings UI also actively misrepresents the true enforcement state (shows "Allow" while nehelper enforces "denied") with no indication to the user that anything is wrong. This is likely not Chrome-specific — any app relying on Local Network access (smart-home apps, casting/streaming apps, IoT config tools) would hit the identical wall once a Mac's nesessionmanager enters this state. Also filed via Feedback Assistant. Happy to share the full decoded netlog trace if useful — didn't attach it here to keep this post scannable, but can paste the additional detail on request.
1
0
40
21h
SecKeychainGetStatus returns varying errors after SecKeychainOpen succeeds on macOS 26.6.2
Hi, so far i've been using the following API Call Sequence in order to check the keychain status prior to using one of the certificates inside the keychain for signing or verifying remote tls connection. // Step 1: Open keychain SecKeychainRef keychain = nil; OSStatus status = SecKeychainOpen(keychainPath, &keychain); // Result: errSecSuccess (0) — always succeeds, returns valid ref // Step 2: Get keychain status SecKeychainStatus keychainStatus = 0; status = SecKeychainGetStatus(keychain, &keychainStatus); // Result: FAILS : see table below I observed SecKeychainGetStatus return errSecInternalError or errSecInvalidHandle │ Process │ Keychain │ Error │ Code │ │ GUI App │ login.keychain. | errSecInternalError │ -26276 │ │ GUI App │ login.keychain | errSecInvalidHandle │ -25308 │ │ GUI App │ /Library/Keychains/System.keychain | errSecInvalidHandle │ -25308 │ │ Daemon │ /Library/Keychains/System.keychain │ errSecInvalidHandle │ -25308 │ SecKeychainOpen always returns errSecSuccess with a non-null SecKeychainRef SecKeychainGetStatus fails immediately when called on that reference The error for login.keychain varies between calls (not deterministic) The error for System.keychain is consistently errSecInvalidHandle Issue is 100% reproducible. every keychain access attempt fails Started immediately after macOS 26.6.2 upgrade Do you know if there were any changes in 26.6.2 that could have caused this behavior? If this is expected, how should I address it? Thanks
1
0
48
21h
IncludeAllNetworks with excludeRoutes do not seem to work together
When I set IncludeAllNetworks in my VPN profile along with the excludeRoutes for traffic I want to go outside of the tunnel, I see the exclude routes being added to the the route table but when we try and to connect on those hosts something is setting a route to the TUN interface and ignoring the excluded routes in the settings. I'm assuming that some policy before any route table is being looked at is doing this but does that then mean IncludeAllNetworks=true and excludeRoutes are actually incompatible? Is this documented and I just missed it?
2
0
49
1d
NEURLFilterControlProvider: stop(reason:) always receives .none, and is skipped in some teardown paths
Testing NEURLFilterControlProvider on iOS 26.6, I've measured two behaviours around stop(reason:) that I can't reconcile with the documentation, and I'd like to know whether either is intended. Setup: development-signed build, filter configured and running, instrumented stop(reason:) that logs the reason and then emits elapsed-time markers. All timings below are from device log archives collected with "log collect --device". The reason parameter is always .none nesessionmanager records a specific stop reason for itself, then passes .none (0) to the provider. Two different user actions, two different internal reasons, same .none delivered. Disabling via NEURLFilterManager (isEnabled = false, saveToPreferences): 15:20:12.173 nesessionmanager: Setting last stop reason to 31 15:20:12.175 MyProvider: stop() entered, reason=0 (none) 15:20:14.208 MyProvider: stop() completed after 2032ms 15:20:14.209 nesessionmanager: status changed to disconnected, last stop reason Configuration was disabled Disabling the filter from iOS Settings: 15:25:04.167 nesessionmanager: Setting last stop reason to 1 15:25:04.169 MyProvider: stop() entered, reason=0 (none) 15:25:06.198 MyProvider: stop() completed after 2028ms 15:25:06.200 nesessionmanager: status changed to disconnected, last stop reason Stop command received The system clearly knows why the filter stopped, and the values it uses (31, 1) are outside the NEProviderStopReason range, so there appears to be a richer internal enum that isn't mapped through to the provider. Is .none what a URL filter control provider should expect in all cases? If so, is there any supported way for the provider to distinguish a deliberate user disable from system settings, say, an in-app disable, app update or a configuration reload? Is stop(reason:) guaranteed to be called? I do cleanup work in stop(), so I want to know whether it is a reliable lifecycle callback or a best-effort one. I found at least one teardown path where it is skipped entirely. When the configuration is removed as part of the app being deleted, the session is torn down without the provider ever being invoked. The extension is terminated roughly 355 ms before the configuration removal: 15:33:59.361 launchd: service inactive: MyProvider, leaving extension group 15:33:59.363 runningboardd: Executing termination request 15:33:59.431 launchd: remove all extension instances ... total of 0 extension instances were found to remove 15:33:59.716 nesessionmanager: configuration has been removed, stopping 15:33:59.716 nesessionmanager: Setting last stop reason to 32 15:33:59.717 nesessionmanager: plugin NEURLFilterPlugin(...) disposed 15:33:59.717 nesessionmanager: status changed to disconnected, last stop reason Configuration was removed No stop() call appears anywhere in the archive, and the plugin is disposed rather than stopped. The whole teardown takes one millisecond. The ordering looks like the cause: by the time nesessionmanager removes the configuration, the extension process is already gone, so there is nothing left to call stop() on. Thread 713975 describes stopTunnel being called with .providerDisabled in the equivalent situation for a packet tunnel provider, so the behaviour appears to differ by provider type. So my question is about the contract rather than this specific path: should a URL filter control provider treat stop(reason:) as guaranteed, or as best-effort? If it is best-effort, are there other teardown paths where it is skipped, so I can make sure nothing important depends on it running?
1
0
313
1d
Can Multiple Transparent Proxies Work Simultaneously on macOS?
Hi everyone, I’m looking for some clarification regarding "Transparent Proxy configurations on macOS". We have a requirement where multiple security/networking solutions may need to use a "Transparent Proxy" on the same macOS device. For example, one solution may be used for web security/SSL inspection while another solution is required for a different security or network traffic use case. My questions are: 1.Does macOS support configuring and running multiple Transparent Proxy providers simultaneously on the same device? 2. If multiple Transparent Proxy configurations are deployed through MDM, how does macOS determine which proxy handles the traffic? 3.Is there any limitation on the number of Transparent Proxy configurations/providers that can be configured? 4.Can multiple Transparent Proxy providers coexist if they handle different traffic, applications, or network interfaces? 5. If multiple providers are configured, is there a supported mechanism to define priority, ordering, or traffic routing between them? 6. Are there any differences or limitations across recent macOS versions, particularly macOS 15 and macOS 26? 7. Is there any Apple documentation or recommended architecture for deploying multiple Transparent Proxy providers on the same Mac? If anyone has implemented or tested a setup with multiple Transparent Proxy providers on macOS, I’d appreciate any insights, documentation, or real-world experience. Thanks! Vijay
1
0
120
1d
Memory leak in CFNetwork (PACClient/PACQuery) when using NETransparentProxyProvider with Auto Proxy Discovery enabled
Hello, I have encountered unexpected behavior when running a Network Extension that implements NETransparentProxyProvider. This extension is part of a DLP (Data Loss Prevention) solution. If the "Auto proxy discovery" option is enabled for the Wi-Fi connection on the managed host, the leaks tool reports memory leaks with the following root cycles: ... 11 (1.03K) ROOT CYCLE: <CFRunLoopSource 0xa430cc540> [192] 10 (864 bytes) ROOT CYCLE: <std::__shared_ptr_emplace<PAC::PACClient> 0xa430f4000> [224] CYCLE BACK TO <CFRunLoopSource 0xa430cc540> [192] 6 (400 bytes) ROOT CYCLE: <std::__shared_ptr_emplace<PAC::PACQuery> 0xa43118080> [128] 2 (80 bytes) ROOT CYCLE: 0xa42ca9000 [32] 1 (48 bytes) ROOT CYCLE: <__NSMallocBlock__ 0xa42804de0> [48] CFNetwork invocation function for block in PAC::PACClient::initialize(void const*, __CFURL cons..." 1 (32 bytes) ROOT CYCLE: <std::__shared_ptr_pointer<BlockHolderVar<__CFString const*, __CFData const*, std::shared_ptr<__CFArray const>, std::shared_ptr<__CFError>>*, SmartBlockWithArgs<__CFString const*, __CFData const*, std::shared_ptr<__CFArray const>, std::shared_ptr<__CFError>>::Deleter> 0xa4343da80> [32] 2 (160 bytes) <NSURL 0xa42840310> [112] 1 (48 bytes) _clients --> <CFString 0xa42c08fc0> [48] 1 (160 bytes) <NWConcrete_nw_pac_resolver 0xa4280cb40> [160] 1 (48 bytes) <CFError 0xa42804ed0> [48] 1 (32 bytes) <std::__shared_ptr_pointer<__CFError*, Deleter_CFRelease> 0xa4343dc20> [32] ... 11 (1.03K) ROOT CYCLE: <CFRunLoopSource 0xa43128540> [192] 10 (864 bytes) ROOT CYCLE: <std::__shared_ptr_emplace<PAC::PACClient> 0xa430f4a80> [224] CYCLE BACK TO <CFRunLoopSource 0xa43128540> [192] 6 (400 bytes) ROOT CYCLE: <std::__shared_ptr_emplace<PAC::PACQuery> 0xa43118880> [128] 2 (80 bytes) ROOT CYCLE: 0xa428105e0 [32] 1 (48 bytes) ROOT CYCLE: <__NSMallocBlock__ 0xa428887b0> [48] CFNetwork invocation function for block in PAC::PACClient::initialize(void const*, __CFURL cons..." 1 (32 bytes) ROOT CYCLE: <std::__shared_ptr_pointer<BlockHolderVar<__CFString const*, __CFData const*, std::shared_ptr<__CFArray const>, std::shared_ptr<__CFError>>*, SmartBlockWithArgs<__CFString const*, __CFData const*, std::shared_ptr<__CFArray const>, std::shared_ptr<__CFError>>::Deleter> 0xa4343f5c0> [32] 2 (160 bytes) <NSURL 0xa428424c0> [112] 1 (48 bytes) _clients --> <CFString 0xa42c0a640> [48] 1 (160 bytes) <NWConcrete_nw_pac_resolver 0xa4280d7c0> [160] 1 (48 bytes) <CFError 0xa42888390> [48] 1 (32 bytes) <std::__shared_ptr_pointer<__CFError*, Deleter_CFRelease> 0xa4343f4c0> [32] ... The extension creates an nw_connection_t to the remote host for each handled flow like this: nw_parameters_t parameters = nw_parameters_create_secure_tcp(NW_PARAMETERS_DISABLE_PROTOCOL, NW_PARAMETERS_DEFAULT_CONFIGURATION); nw_endpoint_t connectTo = nw_endpoint_create_host([endpoint.hostname UTF8String], [endpoint.port UTF8String]); nw_connection_t connection = nw_connection_create(connectTo, parameters); When "Auto proxy discovery" is disabled, everything works as expected, and no memory leaks or issues are observed. Could you please advise on how to resolve or work around this issue? Thank you in advance!
1
0
185
1d
NetworkExtension URL Filter stops during startup only in TestFlight (NEAgentURLFilterErrorDomain Code=3, NEMembershipCheckerErrorDomain Code=3)
Hi Apple Developer Support / community, I am seeing a URL filter startup failure only in TestFlight builds. The same code path works in development and Ad Hoc builds. App setup: Host app bundle id: com.expleo.protectus.filter.main URL filter control extension bundle id: com.expleo.protectus.filter.main.buf Extension point: com.apple.networkextension.url-filter-control Using NEURLFilterManager / NEURLFilterControlProvider on iOS 26.x App Group and network extension entitlements are configured on host + extension Observed behavior: Extension process starts successfully (pid created) Status changes to starting Then updatePrefilterWithCompletionHandler runs Immediately after, plugin transitions to stopping with error 3 System retries in a loop Key logs: Error Domain=NEAgentURLFilterErrorDomain Code=3 Failed to startFilter NEPIRChecker start block reports: Error Domain=com.apple.CipherML Code=1100 Underlying Error Domain=com.apple.CipherML Code=1800 Message says details are redacted Example sequence: NEURLFilterPlugin ... started with pid ... status changed to starting updatePrefilterWithCompletionHandler enter acceptAgentClients enter setStatus:error ... NEAgentURLFilterErrorDomain Code=3 status changed to stopping with error 3 extension disposed / teardown repeats Important detail: This failure is reproducible in TestFlight only. Same code and configuration works in development and Ad Hoc builds. What we already checked: Extension launches and is discovered correctly by neagent App/extension bundle identifiers are correct App group and network extension entitlements are present in source and archive checks We tested startup gating around local bloom/prefilter readiness We still get NEMembershipCheckerErrorDomain Code=3 with CipherML 1100/1800 in TestFlight Questions: Is NEMembershipCheckerErrorDomain Code=3 in this startup path known to indicate PIR membership/status validation failure in distribution context? Are there TestFlight-specific prerequisites or server-side requirements for PIR/CipherML path that differ from development/Ad Hoc? Is there any supported way to get non-redacted diagnostic details for CipherML 1100/1800 (beyond sysdiagnose submission)? Are there recommended fail-open/fail-closed startup patterns when PIR status is temporarily unavailable? If needed, I can provide: Full sysdiagnose timestamped bundle Exact iOS version and device model Repro steps from clean install Full log stream around NEPIRChecker and NEURLFilterPlugin transitions Thanks in advance.
15
0
1.2k
1w
Best practices for handling nw_connection_state_waiting in Transparent Proxy
I am working on a Network Extension (Transparent Proxy) which is used by a DLP to prevent data leaks over the network. For each incoming NEAppProxyTCPFlow, the extension instantiates a custom wrapper object that creates an outbound nw_connection_t to the target host and port using Network framework. When a client application connects to unreachable or blocked ports (e.g., 5222), our extension proxies this connection. As the destination is unreachable, the newly created connection transitions into nw_connection_state_waiting in Network Extension. Since macOS keeps nw_connection_t in the nw_connection_state_waiting state indefinitely, such connections cause system resource leaks. Over time, this leads to: exhaustion of system file descriptors and sockets. system-wide network unavailability until the extension process is killed. Could you provide best-practice recommendations for handling nw_connection_state_waiting in a Network Extension to prevent such resource leaks?
6
0
351
1w
Using URL Filter + Packet Tunnel Provider for blocked URL statistics and App Store approval
Hi Apple Developer Team, We have an iOS app using Network Extension URL Filtering for content filtering. The filtering works, but we need to maintain statistics such as: Number of blocked/allowed URLs Blocked domains/URLs Browser-specific statistics We don't currently see an API from the URL Filter that reliably provides the blocked URL event/details, we already say the latest introduction of reportEndPoint https://developer.apple.com/documentation/networkextension/neurlfiltermanager/reportendpoint?changes=_3,_3, we do not need it for supervised devices and that is mainly designed for supervised devices. We are considering using NEPacketTunnelProvider alongside the URL Filter to collect network-level statistics while keeping the URL Filter responsible for the actual blocking. Our concern is that Could you please clarify: Is it supported to use URL/Content Filter + NEPacketTunnelProvider together for this purpose? Would using Packet Tunnel to collect statistics/network telemetry be considered a misuse of NEPacketTunnelProvider, since it is primarily intended for VPN functionality? Does adding the packet-tunnel-provider Network Extension entitlement require separate Apple approval? Could this architecture create an App Store review/distribution issue? Is there an Apple-supported API for obtaining the URL/domain and block decision directly from the URL/Content Filter, which would be preferable to monitoring packets? Our goal is not to replace the content filter with Packet Tunnel. We want to keep filtering in the appropriate Network Extension and use the appropriate mechanism to maintain browser-specific blocked/allowed statistics. Thank you.
1
0
143
1w
Potential Network Extension memory leak
I've been investigating memory consumption issues with a network extension. It seems as though the "leak" exists within the network extension framework. Looking at a memory graph, there appears to be a _socketFlows dictionary or similar in the network extension framework that holds all of the flows and they continue to pile up and consume memory. The problem seems to be particularly bad when I leave my MacBook plugged in and running over the weekend and come back on Monday. For instance, in that time period, the memory consumption grew from <100MB to >1GB. To try to narrow this down to see if it was an "us" problem or truly in the framework, I installed Objective-See Foundation's Lulu tool, which also uses a network extension. It similarly saw memory grow from around 30MB or less to 600MB in the same time frame. Has anyone else seen this? We do have an open feedback ticket FB18731867 that might be related that has to do with seeing multiple instances of the same data filter provider started and maybe running in a network extension.
4
0
600
2w
Prevent multiple DNS Proxy Filter when switching users
Hello Team, We have a System Extension with Provider Type "DNS Proxy". We have embedded the System Extension in GUI target which registered as LaunchAgent. We found NEDNSProxyManager saves the proxy configuration in the caller's preferences. Due to that we see a prompt for Network Extension when switching users. On allowing that we see multiple DNS filter in the System Settings->Network->Filters even though one DNS Filter can enabled which is annoying. Question 1: Is this expected for non MDM users? Are the users expected to authorise Network extension when switching users. Question 2: Is there a way to prevent the multiple DNS filter for both MDM and non MDM users? To prevent multiple filters, we identified a solution to embed the System Extension in our LaunchDaemon target. So the proxy configuration will be save in the root preference. But with this approach we ended up with an error [OSSystemExtensionErrorDomain error 13] during OSSystemExtensionRequest.deactivationRequest. Question 3: Is there a way to avoid OSSystemExtensionErrorDomain 13 when deactivating System extension from our LaunchDaemon process? Question 4: What is the best practice in terms of embedding and deploying DNS Proxy System Extension for managed and non managed environment. Also if user expected to see multiple DNS filter. I suggest to show the filter that saved for that user's preference. Thank you.
1
0
644
3w
URL Filters not activating on iOS 27 beta
(Also submitted as FB23072541) iOS 27 beta 1 brings a brand new error which ends up resulting in a state of .serverSetupIncomplete: <NEPIRChecker: 0x7de6c79b60>: -[NEPIRChecker start:responseQueue:completionHandler:]_block_invoke - PIR status returned error <Error Domain=com.apple.CipherML Code=1100 "Unable to query status due to errors: Error details were logged and redacted." UserInfo={NSLocalizedDescription=Unable to query status due to errors: Error details were logged and redacted., NSUnderlyingError=0x7de712f4e0 {Error Domain=com.apple.CipherML Code=1800 "Error details were logged and redacted." UserInfo={NSLocalizedDescription=Error details were logged and redacted.}}}> <NEAgentURLFilterExtension: 0x7de6d24e60>: -[NEAgentURLFilterExtension startURLFilter]_block_invoke - Failed to startFilter <Error Domain=NEMembershipCheckerErrorDomain Code=3 "(null)"> What’s a NEMembershipChecker? Member of what? Digging deeper I found these: Failed to prefetch tokens for group 'site.kaylees.Wipr2': Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, LQM: good, NSErrorFailingURLKey=https://pirissuer.kaylees.site/token-key-for-user-token, NSUnderlyingError=0x7517125a40 {Error Domain=NSPOSIXErrorDomain Code=50 "Network is down" UserInfo={NSDescription=Network is down}}, _NSURLErrorPrivacyProxyFailureKey=true, NSLocalizedDescription=The Internet connection appears to be offline.} queryStatus(for:options:) threw an error: Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, LQM: good, NSErrorFailingURLKey=https://pirissuer.kaylees.site/token-key-for-user-token, NSUnderlyingError=0x7517125b00 {Error Domain=NSPOSIXErrorDomain Code=50 "Network is down" UserInfo={NSDescription=Network is down}}, _NSURLErrorPrivacyProxyFailureKey=true, NSLocalizedDescription=The Internet connection appears to be offline.} The connection and the URL mentioned are fine of course, but "Network is down” now? This new problem only affects the App Store version of my app – not present if I install from Xcode. Users report that oddly, having an active VPN on the device works around this bug.
10
3
1.1k
3w
nesessionmanager exits with active Packet Tunnel sessions and causes NEProviderStopReasonInternalError
On iOS 26.5.2 (23F84), we are observing repeated transient VPN restarts caused by the system nesessionmanager process exiting while active NEPacketTunnelProvider sessions still exist. Immediately before the restart, the tunnel is healthy: WireGuard handshakes, connectivity checks, key validation, and PQS checks all succeed. At the time of failure: All XPC connections to nesessionmanager are invalidated. NetworkExtension calls our provider’s stopTunnel(with:) with NEProviderStopReason.internalError (raw value 17). The extension log says: Calling stopTunnelWithReason because: None, followed by IPC detached. UserEventAgent reports: nesessionmanager exited with active sessions, re-launching nesessionmanager to clear agent status. The system launches a new nesessionmanager process and restarts the tunnel through On Demand approximately two seconds later. This occurred 15 times within approximately 44 hours. At least one occurrence coincided with multiple processes being terminated under apparent memory pressure. A sysdiagnose captured approximately one minute after an occurrence, together with the packet tunnel logs and detailed timeline, has been submitted in Feedback Assistant: FB24185635 Is this a known nesessionmanager or jetsam/idle-exit issue on iOS 26.5.2? Is there any supported way for a VPN provider to distinguish this system-level transient restart from an actual provider internal error?
1
0
404
3w
NEURLFilterManager.Error 10 after updating to iOS 26.5.2
I'm seeing an issue with NEURLFilterManager on iOS 26.5.2 and wanted to check if anyone else has encountered this. Our URL Filter implementation was working correctly on previous iOS 26.x releases. After updating devices to iOS 26.5.2, the filter no longer starts. The status changes to: Received filter status change: <FilterStatus: 'stopped' errorMessage: 'The operation couldn’t be completed. (NetworkExtension.NEURLFilterManager.Error error 10.)'> What I've verified The same project and implementation worked on earlier iOS versions. The app and extension have the required Network Extension capabilities and entitlements. The extension bundle identifier matches the one configured in NEURLFilterManager. The extension is embedded correctly in the application. I've tried uninstalling/reinstalling the app and rebuilding with the latest Xcode. The issue is reproducible on iOS 26.5.2. The filter never appears to start, and the status immediately changes to stopped with NEURLFilterManager.Error 10. I'm trying to determine: Has anyone else observed this behavior on iOS 26.5.2? Is there any known regression or change in NEURLFilterManager or URL Filter extensions in this release? Does Error 10 indicate a different failure mode on iOS 26.5.2 than on previous releases? If anyone has experienced the same issue or found a workaround, I'd appreciate any guidance. Thanks!
2
0
509
3w
Network Extension Resources
General: Forums subtopic: App & System Services > Networking DevForums tag: Network Extension Network Extension framework documentation Routing your VPN network traffic article Filtering Network Traffic sample code TN3120 Expected use cases for Network Extension packet tunnel providers technote TN3134 Network Extension provider deployment technote TN3165 Packet Filter is not API technote Network Extension and VPN Glossary forums post Debugging a Network Extension Provider forums post Exporting a Developer ID Network Extension forums post Network Extension Framework Entitlements forums post Network Extension vs ad hoc techniques on macOS forums post Network Extension Provider Packaging forums post NWEndpoint History and Advice forums post Extra-ordinary Networking forums post URL filter: WWDC 2025 Session 234 Filter and tunnel network traffic with NetworkExtension URL filters documentation Filtering traffic by URL sample code Setting up a PIR server for URL filtering sample code Using the Bloom filter tool to configure a URL filter sample code PIR Service Example open source server sample and specifically its documentation Wi-Fi management: Understanding NEHotspotConfigurationErrorInternal forums post See also Networking Resources for general networking resources, including information about Wi-Fi. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
3.9k
Activity
4w
NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Hi, My NEURL Filter configuration (ID 9f3cbff8-63de-4c69-bf68-c19cd1c5d842) was approved on August 5, 2026, but it turned out to be attached to the wrong Apple Developer Team — an old individual account (S5VDH23BBZ) I no longer have access to, instead of my actual organization team, KRKJ76BC7W (SCOTTO), which owns and signs the app (bundle ID com.dropbet.DropBet). I contacted Developer Support, who said they couldn't transfer it and suggested replying to the original approval email — I did (on 08/08, then several times) with no response. I then tried resubmitting the same configuration under the correct team (KRKJ76BC7W), but the portal rejected it with: "A configuration with the same PIR Server Domain already exists." So a fresh submission is technically impossible while the original stays attached to the wrong account — the only real fix is transferring or re-attaching the existing approved configuration to KRKJ76BC7W. Has anyone dealt with this kind of Team ID mix-up before, or know who on the Network Extension / NEURL Filter team could help reassign an approved configuration? Happy to provide any additional details. Thanks in advance.
Replies
5
Boosts
0
Views
702
Activity
14h
Does "Connectivity Assist" bypass NEPacketTunnelProvider DNS interception on iOS 27?
We have a NEPacketTunnelProvider extension that intercepts and modifies DNS responses for specific hostnames as part of its normal operation. On iOS 27, we are seeing this interception being intermittently bypassed. Our extension still receives the DNS query, builds a response, and returns it promptly, but the client occasionally proceeds using a different address, presumably the actual DNS resolution result. This behavior does not reproduce on iOS 26 or earlier. The timing in our logs appears to correlate with the new Connectivity Assist feature (Settings → Wi-Fi), which Apple describes as using cellular data alongside Wi-Fi to improve reliability. Our suspicion is that Connectivity Assist may be performing DNS resolution over a cellular path in parallel, outside the tunnel, causing that resolution path to bypass our provider entirely. We have ruled out response timing and response format issues on our side. Varying the speed and format of our responses does not affect the outcome, suggesting that the behavior is occurring at a layer above the tunnel provider. We have the following questions: Does Connectivity Assist perform DNS resolution on a network path that can bypass an active NEPacketTunnelProvider? Is there any API, entitlement, or supported mechanism to disable Connectivity Assist for an app, or to ensure that all DNS resolution is routed through the active tunnel, similar to previous Wi-Fi Assist opt-out capabilities? Would a NEDNSProxyProvider-based DNS proxy be affected in the same way, or does it operate at a layer that Connectivity Assist cannot bypass? Any guidance, references to relevant documentation, WWDC session content, or confirmation of the expected behavior would be greatly appreciated.
Replies
2
Boosts
0
Views
52
Activity
15h
NEURLFilter & Live Caller ID Lookup approved, but PIR token issuer directory returns 404 on device — filter never activates (serverSetupIncomplete)
Our NEURLFilter (URL Filter) and Live Caller ID Lookup entitlements are both Approved, but on device the URL filter never activates — the NEURLFilter session loops starting → stopped, so no URLs are filtered. App: bundle app.scamzero (App ID 6768433709) URL Filter Config ID: 224e33c9-b03b-44ce-87cd-2153c86908ce Live Caller ID Lookup Config ID: 0abdc42b-c98b-4753-8af4-9334d42abdb8 Device: iPhone on iOS 26. Test account has the paid plan that enables the feature. The system log shows the failure is fetching the Privacy Pass token issuer directory through Apple's relay (gateway.icloud.com), not our backend: ciphermld : Failed to fetch Token Issuer Directory. URL: https://gateway.icloud.com/pat-issuer-directory?issuer=issuer.scamzero.app Status Code: 404 → NEURLFilterPlugin setStatus:error — NEAgentURLFilterErrorDomain Code=3 → NESMURLFilterSession status changed to stopping with error 3 → prefilterCleanup (removes the prefilter mmap) → session restarts → loop This looks like NEURLFilterManager.Error.serverSetupIncomplete (9). What we have already verified on our side (everything conforms): We run Apple's unmodified reference PIRService (from apple/pir-service-example). Our issuer directory at https://issuer.scamzero.app/.well-known/private-token-issuer-directory returns 200 with valid token-keys (token-type 2) and issuer-request-uri. OHTTP gateway (gateway.scamzero.app/ohttp-configs and /gateway), PIR service (service.scamzero.app), use case app.scamzero.url.filtering, bearer token AAAA, DNS TXT apple-url-filter=app.scamzero, and the validation URL apple.com/url-filter-test = 1 are all configured. Our pre-launch checks pass. The precomputed Bloom prefilter loads on device with the correct bit/hash/seed and ~37k domains. Key observation: our OHTTP gateway logs show zero successful OHTTP requests from Apple's infrastructure since Aug 10, and gateway.icloud.com/pat-issuer-directory?issuer=issuer.scamzero.app returns 404 on device. This suggests our Privacy Pass issuer is not registered/validated in Apple's PAT issuer directory, even though both entitlements are Approved. Question: How can we get our Privacy Pass issuer (issuer.scamzero.app) registered/validated in Apple's token issuer directory for the use cases app.scamzero.url.filtering and Live Caller ID Lookup? The entitlements are approved, but the on-device token issuer directory lookup fails with 404, which prevents the filter from ever activating. Happy to file a Feedback with a sysdiagnose if useful.
Replies
1
Boosts
0
Views
79
Activity
21h
nesessionmanager infinite retry loop causes permanent, unfixable Local Network Access denial (System Settings UI misrepresents actual enforcement state)
Summary On macOS 26.6.2 (25G83) (Tahoe), Chrome fails to load pages hosted on private/local IP addresses (e.g. http://192.168.0.43/, a home AV receiver's web setup page) with ERR_ADDRESS_UNREACHABLE, while Safari loads the identical URL without issue on the same Mac, same network. ping to the target IP succeeds normally. System Settings > Privacy & Security > Local Network shows "Allow" for Chrome — but this is not what's actually being enforced. Traced the root cause to nesessionmanager stuck in an infinite retry loop when attempting to install/update NetworkExtension path-rule policies. Because the daemon never completes a successful policy install, nehelper (the actual enforcement point) continues serving a stale cached "denied" decision indefinitely, regardless of what the Settings UI shows or how many times the toggle is flipped. Key evidence Chrome netlog (chrome://net-export/) shows a genuine TCP connect attempt (not an early permission rejection): text TCP_CONNECT_ATTEMPT --> address = "192.168.0.43:80" -TCP_CONNECT_ATTEMPT --> os_error = 65 -TCP_CONNECT --> net_error = -109 (ERR_ADDRESS_UNREACHABLE) os_error = 65 is BSD EHOSTUNREACH, returned by the kernel at the connect() syscall. Unified log (log stream --predicate 'subsystem == "com.apple.networkextension"') shows the actual enforcement decision: text nehelper: UUID cache hit for com.google.Chrome nehelper: Local network denied by preference for Google Chrome (com.google.Chrome) This reproduced identically across multiple attempts, minutes apart, and survived sudo pkill -f nehelper — confirming the decision is persisted, not just an in-memory cache. While toggling the Local Network switch in System Settings, expecting a pathRules dump, the log instead showed: text NESMPathControllerSession[...]: No UUIDs in the cache for PathRuleDefaultNonSystemIdentifier, populating the cache from the path rules NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 1 NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 2 NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 3 NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 4 NESMPathControllerSession[...]: Will reinstall policies after 2000 milliseconds, retry 5 The retry counter kept incrementing with no observed successful completion, meaning any change made via the System Settings toggle can never actually propagate to nehelper. Also confirmed Local Network privacy is not TCC-backed at all: text $ sudo tccutil reset LocalNetwork tccutil: Failed to reset LocalNetwork $ sudo tccutil reset LocalNetwork com.google.Chrome tccutil: Failed to reset LocalNetwork approval status for com.google.Chrome Both fail outright rather than erroring on bad usage, confirming this permission lives entirely in the NetworkExtension path-rule system, with no supported reset command. What did not fix it Toggling the Settings UI switch off/on sudo tccutil reset SystemPolicyNetworkVolumes (wrong TCC service — doesn't apply here) sudo tccutil reset LocalNetwork (fails, see above) Full clean reinstall of Chrome, including all Application Support/Caches/Preferences Safe Mode boot sudo pkill -f nehelper Full normal system restart Launching Chrome with --no-sandbox (rules out Chromium's own internal sandbox as a factor — this is a system-level enforcement, not a Chromium-side block) Working fix Requires temporarily disabling SIP: text In macOS Recovery (csrutil only works from Recovery, not Safe Mode): csrutil disable Back in normal macOS: sudo rm /Library/Preferences/com.apple.networkextension.plist Back in Recovery: csrutil enable Restart normally. nesessionmanager rebuilds the NetworkExtension policy state from scratch on next boot. System Settings > Privacy & Security > Local Network shows a clean list afterward (also clears the separate, previously-known bug where every Chrome auto-update was creating a new duplicate entry in that list rather than updating the existing one). Chrome's next navigation attempt to a local IP correctly triggers a fresh permission prompt, and functions normally once granted. Why this matters Apple's own TN3179 states there's no supported way to reset an app's Local Network privilege to "undetermined." This bug compounds that: once nesessionmanager gets stuck in this retry loop, there is no path back to a working state short of disabling SIP and manually deleting a system preference file. The Settings UI also actively misrepresents the true enforcement state (shows "Allow" while nehelper enforces "denied") with no indication to the user that anything is wrong. This is likely not Chrome-specific — any app relying on Local Network access (smart-home apps, casting/streaming apps, IoT config tools) would hit the identical wall once a Mac's nesessionmanager enters this state. Also filed via Feedback Assistant. Happy to share the full decoded netlog trace if useful — didn't attach it here to keep this post scannable, but can paste the additional detail on request.
Replies
1
Boosts
0
Views
40
Activity
21h
SecKeychainGetStatus returns varying errors after SecKeychainOpen succeeds on macOS 26.6.2
Hi, so far i've been using the following API Call Sequence in order to check the keychain status prior to using one of the certificates inside the keychain for signing or verifying remote tls connection. // Step 1: Open keychain SecKeychainRef keychain = nil; OSStatus status = SecKeychainOpen(keychainPath, &keychain); // Result: errSecSuccess (0) — always succeeds, returns valid ref // Step 2: Get keychain status SecKeychainStatus keychainStatus = 0; status = SecKeychainGetStatus(keychain, &keychainStatus); // Result: FAILS : see table below I observed SecKeychainGetStatus return errSecInternalError or errSecInvalidHandle │ Process │ Keychain │ Error │ Code │ │ GUI App │ login.keychain. | errSecInternalError │ -26276 │ │ GUI App │ login.keychain | errSecInvalidHandle │ -25308 │ │ GUI App │ /Library/Keychains/System.keychain | errSecInvalidHandle │ -25308 │ │ Daemon │ /Library/Keychains/System.keychain │ errSecInvalidHandle │ -25308 │ SecKeychainOpen always returns errSecSuccess with a non-null SecKeychainRef SecKeychainGetStatus fails immediately when called on that reference The error for login.keychain varies between calls (not deterministic) The error for System.keychain is consistently errSecInvalidHandle Issue is 100% reproducible. every keychain access attempt fails Started immediately after macOS 26.6.2 upgrade Do you know if there were any changes in 26.6.2 that could have caused this behavior? If this is expected, how should I address it? Thanks
Replies
1
Boosts
0
Views
48
Activity
21h
IncludeAllNetworks with excludeRoutes do not seem to work together
When I set IncludeAllNetworks in my VPN profile along with the excludeRoutes for traffic I want to go outside of the tunnel, I see the exclude routes being added to the the route table but when we try and to connect on those hosts something is setting a route to the TUN interface and ignoring the excluded routes in the settings. I'm assuming that some policy before any route table is being looked at is doing this but does that then mean IncludeAllNetworks=true and excludeRoutes are actually incompatible? Is this documented and I just missed it?
Replies
2
Boosts
0
Views
49
Activity
1d
NEURLFilterControlProvider: stop(reason:) always receives .none, and is skipped in some teardown paths
Testing NEURLFilterControlProvider on iOS 26.6, I've measured two behaviours around stop(reason:) that I can't reconcile with the documentation, and I'd like to know whether either is intended. Setup: development-signed build, filter configured and running, instrumented stop(reason:) that logs the reason and then emits elapsed-time markers. All timings below are from device log archives collected with "log collect --device". The reason parameter is always .none nesessionmanager records a specific stop reason for itself, then passes .none (0) to the provider. Two different user actions, two different internal reasons, same .none delivered. Disabling via NEURLFilterManager (isEnabled = false, saveToPreferences): 15:20:12.173 nesessionmanager: Setting last stop reason to 31 15:20:12.175 MyProvider: stop() entered, reason=0 (none) 15:20:14.208 MyProvider: stop() completed after 2032ms 15:20:14.209 nesessionmanager: status changed to disconnected, last stop reason Configuration was disabled Disabling the filter from iOS Settings: 15:25:04.167 nesessionmanager: Setting last stop reason to 1 15:25:04.169 MyProvider: stop() entered, reason=0 (none) 15:25:06.198 MyProvider: stop() completed after 2028ms 15:25:06.200 nesessionmanager: status changed to disconnected, last stop reason Stop command received The system clearly knows why the filter stopped, and the values it uses (31, 1) are outside the NEProviderStopReason range, so there appears to be a richer internal enum that isn't mapped through to the provider. Is .none what a URL filter control provider should expect in all cases? If so, is there any supported way for the provider to distinguish a deliberate user disable from system settings, say, an in-app disable, app update or a configuration reload? Is stop(reason:) guaranteed to be called? I do cleanup work in stop(), so I want to know whether it is a reliable lifecycle callback or a best-effort one. I found at least one teardown path where it is skipped entirely. When the configuration is removed as part of the app being deleted, the session is torn down without the provider ever being invoked. The extension is terminated roughly 355 ms before the configuration removal: 15:33:59.361 launchd: service inactive: MyProvider, leaving extension group 15:33:59.363 runningboardd: Executing termination request 15:33:59.431 launchd: remove all extension instances ... total of 0 extension instances were found to remove 15:33:59.716 nesessionmanager: configuration has been removed, stopping 15:33:59.716 nesessionmanager: Setting last stop reason to 32 15:33:59.717 nesessionmanager: plugin NEURLFilterPlugin(...) disposed 15:33:59.717 nesessionmanager: status changed to disconnected, last stop reason Configuration was removed No stop() call appears anywhere in the archive, and the plugin is disposed rather than stopped. The whole teardown takes one millisecond. The ordering looks like the cause: by the time nesessionmanager removes the configuration, the extension process is already gone, so there is nothing left to call stop() on. Thread 713975 describes stopTunnel being called with .providerDisabled in the equivalent situation for a packet tunnel provider, so the behaviour appears to differ by provider type. So my question is about the contract rather than this specific path: should a URL filter control provider treat stop(reason:) as guaranteed, or as best-effort? If it is best-effort, are there other teardown paths where it is skipped, so I can make sure nothing important depends on it running?
Replies
1
Boosts
0
Views
313
Activity
1d
Can Multiple Transparent Proxies Work Simultaneously on macOS?
Hi everyone, I’m looking for some clarification regarding "Transparent Proxy configurations on macOS". We have a requirement where multiple security/networking solutions may need to use a "Transparent Proxy" on the same macOS device. For example, one solution may be used for web security/SSL inspection while another solution is required for a different security or network traffic use case. My questions are: 1.Does macOS support configuring and running multiple Transparent Proxy providers simultaneously on the same device? 2. If multiple Transparent Proxy configurations are deployed through MDM, how does macOS determine which proxy handles the traffic? 3.Is there any limitation on the number of Transparent Proxy configurations/providers that can be configured? 4.Can multiple Transparent Proxy providers coexist if they handle different traffic, applications, or network interfaces? 5. If multiple providers are configured, is there a supported mechanism to define priority, ordering, or traffic routing between them? 6. Are there any differences or limitations across recent macOS versions, particularly macOS 15 and macOS 26? 7. Is there any Apple documentation or recommended architecture for deploying multiple Transparent Proxy providers on the same Mac? If anyone has implemented or tested a setup with multiple Transparent Proxy providers on macOS, I’d appreciate any insights, documentation, or real-world experience. Thanks! Vijay
Replies
1
Boosts
0
Views
120
Activity
1d
Memory leak in CFNetwork (PACClient/PACQuery) when using NETransparentProxyProvider with Auto Proxy Discovery enabled
Hello, I have encountered unexpected behavior when running a Network Extension that implements NETransparentProxyProvider. This extension is part of a DLP (Data Loss Prevention) solution. If the "Auto proxy discovery" option is enabled for the Wi-Fi connection on the managed host, the leaks tool reports memory leaks with the following root cycles: ... 11 (1.03K) ROOT CYCLE: <CFRunLoopSource 0xa430cc540> [192] 10 (864 bytes) ROOT CYCLE: <std::__shared_ptr_emplace<PAC::PACClient> 0xa430f4000> [224] CYCLE BACK TO <CFRunLoopSource 0xa430cc540> [192] 6 (400 bytes) ROOT CYCLE: <std::__shared_ptr_emplace<PAC::PACQuery> 0xa43118080> [128] 2 (80 bytes) ROOT CYCLE: 0xa42ca9000 [32] 1 (48 bytes) ROOT CYCLE: <__NSMallocBlock__ 0xa42804de0> [48] CFNetwork invocation function for block in PAC::PACClient::initialize(void const*, __CFURL cons..." 1 (32 bytes) ROOT CYCLE: <std::__shared_ptr_pointer<BlockHolderVar<__CFString const*, __CFData const*, std::shared_ptr<__CFArray const>, std::shared_ptr<__CFError>>*, SmartBlockWithArgs<__CFString const*, __CFData const*, std::shared_ptr<__CFArray const>, std::shared_ptr<__CFError>>::Deleter> 0xa4343da80> [32] 2 (160 bytes) <NSURL 0xa42840310> [112] 1 (48 bytes) _clients --> <CFString 0xa42c08fc0> [48] 1 (160 bytes) <NWConcrete_nw_pac_resolver 0xa4280cb40> [160] 1 (48 bytes) <CFError 0xa42804ed0> [48] 1 (32 bytes) <std::__shared_ptr_pointer<__CFError*, Deleter_CFRelease> 0xa4343dc20> [32] ... 11 (1.03K) ROOT CYCLE: <CFRunLoopSource 0xa43128540> [192] 10 (864 bytes) ROOT CYCLE: <std::__shared_ptr_emplace<PAC::PACClient> 0xa430f4a80> [224] CYCLE BACK TO <CFRunLoopSource 0xa43128540> [192] 6 (400 bytes) ROOT CYCLE: <std::__shared_ptr_emplace<PAC::PACQuery> 0xa43118880> [128] 2 (80 bytes) ROOT CYCLE: 0xa428105e0 [32] 1 (48 bytes) ROOT CYCLE: <__NSMallocBlock__ 0xa428887b0> [48] CFNetwork invocation function for block in PAC::PACClient::initialize(void const*, __CFURL cons..." 1 (32 bytes) ROOT CYCLE: <std::__shared_ptr_pointer<BlockHolderVar<__CFString const*, __CFData const*, std::shared_ptr<__CFArray const>, std::shared_ptr<__CFError>>*, SmartBlockWithArgs<__CFString const*, __CFData const*, std::shared_ptr<__CFArray const>, std::shared_ptr<__CFError>>::Deleter> 0xa4343f5c0> [32] 2 (160 bytes) <NSURL 0xa428424c0> [112] 1 (48 bytes) _clients --> <CFString 0xa42c0a640> [48] 1 (160 bytes) <NWConcrete_nw_pac_resolver 0xa4280d7c0> [160] 1 (48 bytes) <CFError 0xa42888390> [48] 1 (32 bytes) <std::__shared_ptr_pointer<__CFError*, Deleter_CFRelease> 0xa4343f4c0> [32] ... The extension creates an nw_connection_t to the remote host for each handled flow like this: nw_parameters_t parameters = nw_parameters_create_secure_tcp(NW_PARAMETERS_DISABLE_PROTOCOL, NW_PARAMETERS_DEFAULT_CONFIGURATION); nw_endpoint_t connectTo = nw_endpoint_create_host([endpoint.hostname UTF8String], [endpoint.port UTF8String]); nw_connection_t connection = nw_connection_create(connectTo, parameters); When "Auto proxy discovery" is disabled, everything works as expected, and no memory leaks or issues are observed. Could you please advise on how to resolve or work around this issue? Thank you in advance!
Replies
1
Boosts
0
Views
185
Activity
1d
VPN node telemetry data
Hello, I making VPN client app and would like to clarify Apple Guideline 5.4 article: "VPN apps may not sell, use, or disclose to third parties any data for any purpose, and must commit to this in their privacy policy", does it mean anonymous nodes/servers telemetry also can't be provided to third parties? Thank you
Replies
1
Boosts
0
Views
617
Activity
1w
NetworkExtension URL Filter stops during startup only in TestFlight (NEAgentURLFilterErrorDomain Code=3, NEMembershipCheckerErrorDomain Code=3)
Hi Apple Developer Support / community, I am seeing a URL filter startup failure only in TestFlight builds. The same code path works in development and Ad Hoc builds. App setup: Host app bundle id: com.expleo.protectus.filter.main URL filter control extension bundle id: com.expleo.protectus.filter.main.buf Extension point: com.apple.networkextension.url-filter-control Using NEURLFilterManager / NEURLFilterControlProvider on iOS 26.x App Group and network extension entitlements are configured on host + extension Observed behavior: Extension process starts successfully (pid created) Status changes to starting Then updatePrefilterWithCompletionHandler runs Immediately after, plugin transitions to stopping with error 3 System retries in a loop Key logs: Error Domain=NEAgentURLFilterErrorDomain Code=3 Failed to startFilter NEPIRChecker start block reports: Error Domain=com.apple.CipherML Code=1100 Underlying Error Domain=com.apple.CipherML Code=1800 Message says details are redacted Example sequence: NEURLFilterPlugin ... started with pid ... status changed to starting updatePrefilterWithCompletionHandler enter acceptAgentClients enter setStatus:error ... NEAgentURLFilterErrorDomain Code=3 status changed to stopping with error 3 extension disposed / teardown repeats Important detail: This failure is reproducible in TestFlight only. Same code and configuration works in development and Ad Hoc builds. What we already checked: Extension launches and is discovered correctly by neagent App/extension bundle identifiers are correct App group and network extension entitlements are present in source and archive checks We tested startup gating around local bloom/prefilter readiness We still get NEMembershipCheckerErrorDomain Code=3 with CipherML 1100/1800 in TestFlight Questions: Is NEMembershipCheckerErrorDomain Code=3 in this startup path known to indicate PIR membership/status validation failure in distribution context? Are there TestFlight-specific prerequisites or server-side requirements for PIR/CipherML path that differ from development/Ad Hoc? Is there any supported way to get non-redacted diagnostic details for CipherML 1100/1800 (beyond sysdiagnose submission)? Are there recommended fail-open/fail-closed startup patterns when PIR status is temporarily unavailable? If needed, I can provide: Full sysdiagnose timestamped bundle Exact iOS version and device model Repro steps from clean install Full log stream around NEPIRChecker and NEURLFilterPlugin transitions Thanks in advance.
Replies
15
Boosts
0
Views
1.2k
Activity
1w
Best practices for handling nw_connection_state_waiting in Transparent Proxy
I am working on a Network Extension (Transparent Proxy) which is used by a DLP to prevent data leaks over the network. For each incoming NEAppProxyTCPFlow, the extension instantiates a custom wrapper object that creates an outbound nw_connection_t to the target host and port using Network framework. When a client application connects to unreachable or blocked ports (e.g., 5222), our extension proxies this connection. As the destination is unreachable, the newly created connection transitions into nw_connection_state_waiting in Network Extension. Since macOS keeps nw_connection_t in the nw_connection_state_waiting state indefinitely, such connections cause system resource leaks. Over time, this leads to: exhaustion of system file descriptors and sockets. system-wide network unavailability until the extension process is killed. Could you provide best-practice recommendations for handling nw_connection_state_waiting in a Network Extension to prevent such resource leaks?
Replies
6
Boosts
0
Views
351
Activity
1w
Using URL Filter + Packet Tunnel Provider for blocked URL statistics and App Store approval
Hi Apple Developer Team, We have an iOS app using Network Extension URL Filtering for content filtering. The filtering works, but we need to maintain statistics such as: Number of blocked/allowed URLs Blocked domains/URLs Browser-specific statistics We don't currently see an API from the URL Filter that reliably provides the blocked URL event/details, we already say the latest introduction of reportEndPoint https://developer.apple.com/documentation/networkextension/neurlfiltermanager/reportendpoint?changes=_3,_3, we do not need it for supervised devices and that is mainly designed for supervised devices. We are considering using NEPacketTunnelProvider alongside the URL Filter to collect network-level statistics while keeping the URL Filter responsible for the actual blocking. Our concern is that Could you please clarify: Is it supported to use URL/Content Filter + NEPacketTunnelProvider together for this purpose? Would using Packet Tunnel to collect statistics/network telemetry be considered a misuse of NEPacketTunnelProvider, since it is primarily intended for VPN functionality? Does adding the packet-tunnel-provider Network Extension entitlement require separate Apple approval? Could this architecture create an App Store review/distribution issue? Is there an Apple-supported API for obtaining the URL/domain and block decision directly from the URL/Content Filter, which would be preferable to monitoring packets? Our goal is not to replace the content filter with Packet Tunnel. We want to keep filtering in the appropriate Network Extension and use the appropriate mechanism to maintain browser-specific blocked/allowed statistics. Thank you.
Replies
1
Boosts
0
Views
143
Activity
1w
Potential Network Extension memory leak
I've been investigating memory consumption issues with a network extension. It seems as though the "leak" exists within the network extension framework. Looking at a memory graph, there appears to be a _socketFlows dictionary or similar in the network extension framework that holds all of the flows and they continue to pile up and consume memory. The problem seems to be particularly bad when I leave my MacBook plugged in and running over the weekend and come back on Monday. For instance, in that time period, the memory consumption grew from <100MB to >1GB. To try to narrow this down to see if it was an "us" problem or truly in the framework, I installed Objective-See Foundation's Lulu tool, which also uses a network extension. It similarly saw memory grow from around 30MB or less to 600MB in the same time frame. Has anyone else seen this? We do have an open feedback ticket FB18731867 that might be related that has to do with seeing multiple instances of the same data filter provider started and maybe running in a network extension.
Replies
4
Boosts
0
Views
600
Activity
2w
Launch Transparent Proxy Network Extension in machine login window on macOS
Hi, Is there a way on macOS to launch Transparent Proxy Network Extension in machine login window? on-demand rule doesn't help. I have this use case that after reboot machine, I want to launch Transparent Proxy Network Extension in machine login window before user log into machine.
Replies
2
Boosts
0
Views
352
Activity
2w
Prevent multiple DNS Proxy Filter when switching users
Hello Team, We have a System Extension with Provider Type "DNS Proxy". We have embedded the System Extension in GUI target which registered as LaunchAgent. We found NEDNSProxyManager saves the proxy configuration in the caller's preferences. Due to that we see a prompt for Network Extension when switching users. On allowing that we see multiple DNS filter in the System Settings->Network->Filters even though one DNS Filter can enabled which is annoying. Question 1: Is this expected for non MDM users? Are the users expected to authorise Network extension when switching users. Question 2: Is there a way to prevent the multiple DNS filter for both MDM and non MDM users? To prevent multiple filters, we identified a solution to embed the System Extension in our LaunchDaemon target. So the proxy configuration will be save in the root preference. But with this approach we ended up with an error [OSSystemExtensionErrorDomain error 13] during OSSystemExtensionRequest.deactivationRequest. Question 3: Is there a way to avoid OSSystemExtensionErrorDomain 13 when deactivating System extension from our LaunchDaemon process? Question 4: What is the best practice in terms of embedding and deploying DNS Proxy System Extension for managed and non managed environment. Also if user expected to see multiple DNS filter. I suggest to show the filter that saved for that user's preference. Thank you.
Replies
1
Boosts
0
Views
644
Activity
3w
URL Filters not activating on iOS 27 beta
(Also submitted as FB23072541) iOS 27 beta 1 brings a brand new error which ends up resulting in a state of .serverSetupIncomplete: <NEPIRChecker: 0x7de6c79b60>: -[NEPIRChecker start:responseQueue:completionHandler:]_block_invoke - PIR status returned error <Error Domain=com.apple.CipherML Code=1100 "Unable to query status due to errors: Error details were logged and redacted." UserInfo={NSLocalizedDescription=Unable to query status due to errors: Error details were logged and redacted., NSUnderlyingError=0x7de712f4e0 {Error Domain=com.apple.CipherML Code=1800 "Error details were logged and redacted." UserInfo={NSLocalizedDescription=Error details were logged and redacted.}}}> <NEAgentURLFilterExtension: 0x7de6d24e60>: -[NEAgentURLFilterExtension startURLFilter]_block_invoke - Failed to startFilter <Error Domain=NEMembershipCheckerErrorDomain Code=3 "(null)"> What’s a NEMembershipChecker? Member of what? Digging deeper I found these: Failed to prefetch tokens for group 'site.kaylees.Wipr2': Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, LQM: good, NSErrorFailingURLKey=https://pirissuer.kaylees.site/token-key-for-user-token, NSUnderlyingError=0x7517125a40 {Error Domain=NSPOSIXErrorDomain Code=50 "Network is down" UserInfo={NSDescription=Network is down}}, _NSURLErrorPrivacyProxyFailureKey=true, NSLocalizedDescription=The Internet connection appears to be offline.} queryStatus(for:options:) threw an error: Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, LQM: good, NSErrorFailingURLKey=https://pirissuer.kaylees.site/token-key-for-user-token, NSUnderlyingError=0x7517125b00 {Error Domain=NSPOSIXErrorDomain Code=50 "Network is down" UserInfo={NSDescription=Network is down}}, _NSURLErrorPrivacyProxyFailureKey=true, NSLocalizedDescription=The Internet connection appears to be offline.} The connection and the URL mentioned are fine of course, but "Network is down” now? This new problem only affects the App Store version of my app – not present if I install from Xcode. Users report that oddly, having an active VPN on the device works around this bug.
Replies
10
Boosts
3
Views
1.1k
Activity
3w
nesessionmanager exits with active Packet Tunnel sessions and causes NEProviderStopReasonInternalError
On iOS 26.5.2 (23F84), we are observing repeated transient VPN restarts caused by the system nesessionmanager process exiting while active NEPacketTunnelProvider sessions still exist. Immediately before the restart, the tunnel is healthy: WireGuard handshakes, connectivity checks, key validation, and PQS checks all succeed. At the time of failure: All XPC connections to nesessionmanager are invalidated. NetworkExtension calls our provider’s stopTunnel(with:) with NEProviderStopReason.internalError (raw value 17). The extension log says: Calling stopTunnelWithReason because: None, followed by IPC detached. UserEventAgent reports: nesessionmanager exited with active sessions, re-launching nesessionmanager to clear agent status. The system launches a new nesessionmanager process and restarts the tunnel through On Demand approximately two seconds later. This occurred 15 times within approximately 44 hours. At least one occurrence coincided with multiple processes being terminated under apparent memory pressure. A sysdiagnose captured approximately one minute after an occurrence, together with the packet tunnel logs and detailed timeline, has been submitted in Feedback Assistant: FB24185635 Is this a known nesessionmanager or jetsam/idle-exit issue on iOS 26.5.2? Is there any supported way for a VPN provider to distinguish this system-level transient restart from an actual provider internal error?
Replies
1
Boosts
0
Views
404
Activity
3w
NEURLFilterManager.Error 10 after updating to iOS 26.5.2
I'm seeing an issue with NEURLFilterManager on iOS 26.5.2 and wanted to check if anyone else has encountered this. Our URL Filter implementation was working correctly on previous iOS 26.x releases. After updating devices to iOS 26.5.2, the filter no longer starts. The status changes to: Received filter status change: <FilterStatus: 'stopped' errorMessage: 'The operation couldn’t be completed. (NetworkExtension.NEURLFilterManager.Error error 10.)'> What I've verified The same project and implementation worked on earlier iOS versions. The app and extension have the required Network Extension capabilities and entitlements. The extension bundle identifier matches the one configured in NEURLFilterManager. The extension is embedded correctly in the application. I've tried uninstalling/reinstalling the app and rebuilding with the latest Xcode. The issue is reproducible on iOS 26.5.2. The filter never appears to start, and the status immediately changes to stopped with NEURLFilterManager.Error 10. I'm trying to determine: Has anyone else observed this behavior on iOS 26.5.2? Is there any known regression or change in NEURLFilterManager or URL Filter extensions in this release? Does Error 10 indicate a different failure mode on iOS 26.5.2 than on previous releases? If anyone has experienced the same issue or found a workaround, I'd appreciate any guidance. Thanks!
Replies
2
Boosts
0
Views
509
Activity
3w